package org.protege.owl.examples.tab;

import java.util.*;
import javax.swing.JTextArea;

public class ResultTable
{
	
	public final static String DONTCARE="___";
	private HashMap<Variable,ArrayList<String>> columns;
	
	private static int fitSize;
	
	public static int getFitSize()
	{
		return fitSize;
	}

	public ResultTable()
	{
		columns=new HashMap<Variable,ArrayList<String>>();
		//columns.get("Test")
	}
	
	
	public ResultTable(ResultTable rt)
	{
		columns=new HashMap<Variable,ArrayList<String>>();
		Iterator<Variable> varIt = rt.getVarialbeSet().iterator();
		while (varIt.hasNext())
		{
			Variable currVar = varIt.next();
			addColumn(currVar,rt.getValuesList(currVar));
		}
	}

	/**
	 * Creates new empty instances column for var. 
	 * 
	 * @param var - reference to variable
	 */
	public void addColumn(Variable var)
	{
		columns.put(var,new ArrayList<String>());
	}
	
	/**
	 * Creates new instances column for var. 
	 * Only references to var and instances are copied
	 * 
	 * @param var - reference to variable
	 * @param inst - list of references to instances
	 */
	public void addColumn(Variable var, List<String> inst)
	{
		ArrayList<String> newInstances = new ArrayList<String>();
		Iterator<String> instIt = inst.iterator();
		while(instIt.hasNext())
		{
			newInstances.add(instIt.next());
		}
		columns.put(var,newInstances);
	}
	
	public void addInstance(Variable var, String instance)
	{
		ArrayList<String> col= columns.get(var);
		col.add(instance);
	}
	
	private List<String> getValuesList(Variable var)
	{
		return columns.get(var);
	}

	public Set<Variable> getVarialbeSet()
	{
		return columns.keySet();
	}
	
	public String getInstance(Variable var, int index)
	{
		return new String(columns.get(var).get(index));
	}
	
	public int size() throws NotUniformSizeException
	{
		int result = 0;
		Iterator<ArrayList<String>> instListIt = columns.values().iterator();
		if (instListIt.hasNext())
			result = instListIt.next().size();
		while (instListIt.hasNext())
			if (instListIt.next().size()!=result)
				throw new NotUniformSizeException();
		return result;
	}
	
	public static ResultTable or(ResultTable t1, ResultTable t2) throws NotUniformSizeException
	{
		int t1size = t1.size();
		int t2size = t2.size();

		Set<Variable> t1keySet = t1.getVarialbeSet();
		Set<Variable> t2keySet = t2.getVarialbeSet();
		
		ResultTable result=new ResultTable(t1);
		
		Set<Variable> commonVars= new HashSet<Variable>(t1keySet);
		commonVars.retainAll(t2keySet);
		
		if (t2keySet.size() > commonVars.size())
		{
			Set<Variable> t2specyficVars = new HashSet<Variable>(t2.getVarialbeSet());
			t2specyficVars.removeAll(t1.getVarialbeSet());
			Iterator<Variable> t2specVarIt = t2specyficVars.iterator();
			while(t2specVarIt.hasNext())
			{
				List<String> dontCares=new ArrayList<String>();	
				for(int i=0; i<t1size; i++)
					dontCares.add(DONTCARE);
				result.addColumn(t2specVarIt.next(),dontCares);
			}
		}
		
		Iterator<Variable> t2VarsIt = t2keySet.iterator();
		while (t2VarsIt.hasNext())
		{
			Variable currVar=t2VarsIt.next();
			Iterator<String> t2instList = t2.getValuesList(currVar).iterator();
			while(t2instList.hasNext())
			{
				result.addInstance(currVar, t2instList.next());
			}
		}
		
		if (t1keySet.size() > commonVars.size())
		{
			Set<Variable> t1specyficVars = new HashSet<Variable>(t1.getVarialbeSet());
			t1specyficVars.removeAll(t2.getVarialbeSet());
			Iterator<Variable> t1specVarIt = t1specyficVars.iterator();
			while(t1specVarIt.hasNext())
			{
				Variable currVar=t1specVarIt.next();
				for(int i=0; i<t2size; i++)
					result.addInstance(currVar,DONTCARE);
			}	
		}
		return result;
	}
	public static ResultTable and(ResultTable t1, ResultTable t2) throws NotUniformSizeException
	{
		return and(t1,t2,null);
	}
	
	public static ResultTable and(ResultTable t1, ResultTable t2, Integer t1INt2) throws NotUniformSizeException
	{
		//System.out.println("---AND BEGIN---");
		fitSize = 0; 
		
		int t1size = t1.size();
		int t2size = t2.size();

		//Set<Variable> t1keySet = t1.getKeySet();
		Set<Variable> t2keySet = t2.getVarialbeSet();
		
		ResultTable result=new ResultTable();
		// hahaha
		
		//System.out.println("AND: SUPER TABLE GENEREATION START");
		ResultTable st = new ResultTable(t1); //super table for comparison
		
		Set<Variable> t2specyficVars = new HashSet<Variable>(t2.getVarialbeSet());
		t2specyficVars.removeAll(t1.getVarialbeSet());
		Iterator<Variable> t2specVarIt = t2specyficVars.iterator();
		
		while (t2specVarIt.hasNext())
		{
			List<String> dontCares=new ArrayList<String>();	
			for(int i=0; i<t1size; i++)
				dontCares.add(DONTCARE);
			st.addColumn(t2specVarIt.next(),dontCares);
		}
		//System.out.println("AND: SUPER TABLE GENERATION END");
		Set<Variable> stKeySet = st.getVarialbeSet();
		Iterator<Variable> stVarsIt = stKeySet.iterator();
		
		//System.out.println("AND: POPULATING RESULT START");

		//adding columns to result table
		while (stVarsIt.hasNext())
		{
			result.addColumn(stVarsIt.next());
		}
		
		//System.out.println("AND: INIT DONE...");
		
		int addCount = 0;
		boolean fitsOnce = false;
		
		for (int j=0; j<t1size; j++)
		{
			fitsOnce = false;
			for (int i=0; i<t2size; i++)
			{
				boolean fits = true;
				Iterator<Variable> t2VarsIt = t2keySet.iterator();
				//System.out.println("AND: CHECKING ROW: "+i*t1size+j);
				while(t2VarsIt.hasNext())
				{
					Variable currVar=t2VarsIt.next();
					if(!instancesEqual(st.getInstance(currVar, j),t2.getInstance(currVar, i)))
					{
						fits = false;
						break;
					}
				}
				//System.out.println("AND: CHECKING ROW END ");
				if (fits)
				{
					if (fitsOnce==false)
					{
						fitsOnce = true;
						fitSize++;
						System.out.println("fitSize++ : " + fitSize);
					}
					//System.out.println("AND: ROW FITS! "+i*t1size+j);
					stVarsIt = stKeySet.iterator();
					while(stVarsIt.hasNext())
					{
						Variable currVar=stVarsIt.next();
						String currStInstance = st.getInstance(currVar, j);
						if(currStInstance.equals(DONTCARE) && t2keySet.contains(currVar))
						{
							String addedInstance =  t2.getInstance(currVar, i);
							result.addInstance(currVar,  t2.getInstance(currVar, i));
							//System.out.println("AND: InstanceAdded:" + addedInstance + "(" + addCount++ +")");
	
						}
						else
						{
							result.addInstance(currVar, currStInstance);
							//System.out.println("AND: InstanceAdded:" + currStInstance + "("+addCount++ +")");
						}
					}
				}
			}
		}
		//System.out.println("AND: POPULATING RESULT END");
		//System.out.println("---AND END---");
		
		if (t1INt2 != null) 
			t1INt2 = fitSize;
		System.out.println("FitSize Set: " + t1INt2);
		return result;
	}
	
	
	private static boolean instancesEqual (String s1, String s2)
	{
		if(s1.equals(s2) || s1.equals(DONTCARE) || s2.equals(DONTCARE))
			return true;
		else 
			return false;
	}
	
	
	
	public void listResultTable(JTextArea textarea)
	{
		try
		{
			listVars(textarea);
			for(int i=0;i<size();i++)
			{	
				listRow(i,textarea);
			}
		}
		catch (NotUniformSizeException e)
		{
			e.printStackTrace();
			textarea.setText("Not Uniform Table Size!!\n");
		}
	}
	
	private void  listRow (int index, JTextArea textarea)
	{
		Iterator<Variable> colIt = columns.keySet().iterator();
		
		textarea.setText(textarea.getText() + "\n");
		while(colIt.hasNext())
		{
			textarea.setText(textarea.getText()+getInstance(colIt.next(),index) + "\t");
		}
		textarea.setText(textarea.getText() + "\n");
	}

	private void  listVars (JTextArea textarea)
	{
		Iterator<Variable> colIt = columns.keySet().iterator();
		
		textarea.setText(textarea.getText() + "\n");
		while(colIt.hasNext())
		{
			textarea.setText(textarea.getText()+colIt.next().name() + "\t");
		}
		textarea.setText(textarea.getText() + "\n");
	}
	
}



